const Ci = Components.interfaces;  
const Cu = Components.utils;  
const Cc = Components.classes;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');  
Cu.import("resource://gre/modules/Services.jsm");

const CLASS_ID = Components.ID('868f58c0-dad7-11e0-9572-0800200c9a66');  
const CLASS_NAME = "OpenID AutoComplete";  
const CONTRACT_ID = '@mozilla.org/autocomplete/search;1?name=net.openid.openid_url';  

function log(aMessage) {
//	  Services.console.logStringMessage("autocomplete: " + aMessage);
}

/**
 * @constructor
 * 
 * @implements {nsIAutoCompleteResult}
 * 
 * @param {string}
 *            searchString
 * @param {number}
 *            searchResult
 * @param {number}
 *            defaultIndex
 * @param {string}
 *            errorDescription
 * @param {Array.
 *            <string>} results
 * @param {Array.
 *            <string>|null=} comments
 */  
function ProviderAutoCompleteResult(searchString, searchResult,  
  defaultIndex, errorDescription, results, comments) {  
  log("constructor");
  this._searchString = searchString;  
  this._searchResult = searchResult;  
  this._defaultIndex = defaultIndex;  
  this._errorDescription = errorDescription;  
  this._results = results;  
  this._comments = comments;  
}  
  
ProviderAutoCompleteResult.prototype = {  
  _searchString: "",  
  _searchResult: 0,  
  _defaultIndex: 0,  
  _errorDescription: "",  
  _results: [],  
  _comments: [],  
  
  /**
	 * @return {string} the original search string
	 */  
  get searchString() {  
    return this._searchString;  
  },  
  
  /**
	 * @return {number} the result code of this result object, either:
	 *         RESULT_IGNORED (invalid searchString) RESULT_FAILURE
	 *         (failure) RESULT_NOMATCH (no matches found) RESULT_SUCCESS
	 *         (matches found)
	 */  
  get searchResult() {  
    return this._searchResult;  
  },  
  
  /**
	 * @return {number} the index of the default item that should be entered
	 *         if none is selected
	 */  
  get defaultIndex() {  
    return this._defaultIndex;  
  },  
  
  /**
	 * @return {string} description of the cause of a search failure
	 */  
  get errorDescription() {  
    return this._errorDescription;  
  },  
  
  /**
	 * @return {number} the number of matches
	 */  
  get matchCount() {  
    return this._results.length;  
  },  
  
  /**
	 * @return {string} the value of the result at the given index
	 */  
  getValueAt: function(index) {  
    return this._results[index];  
  },  
  
  /**
	 * @return {string} the comment of the result at the given index
	 */  
  getCommentAt: function(index) {  
    if (this._comments)  
      return this._comments[index];  
    else  
      return '';  
  },  
  
  /**
	 * @return {string} the style hint for the result at the given index
	 */  
  getStyleAt: function(index) {  
    if (!this._comments || !this._comments[index])  
      return null;  // not a category label, so no special styling
  
    if (index == 0)  
      return 'suggestfirst';  // category label on first line of results
  
    return 'suggesthint';   // category label on any other line of results
  },  
  
  /**
	 * Gets the image for the result at the given index
	 * 
	 * @return {string} the URI to the image to display
	 */  
  getImageAt : function (index) {  
    return '';  
  },  
  
  /**
	 * Removes the value at the given index from the autocomplete results.
	 * If removeFromDb is set to true, the value should be removed from
	 * persistent storage as well.
	 */  
  removeValueAt: function(index, removeFromDb) {  
    this._results.splice(index, 1);  
  
    if (this._comments)  
      this._comments.splice(index, 1);  
  },  
  
  getLabelAt: function(index) { return this._results[index]; },  
  
  QueryInterface: XPCOMUtils.generateQI([ Ci.nsIAutoCompleteResult ])  
};  
  
  
/**
 * @constructor
 * 
 * @implements {nsIAutoCompleteSearch}
 */  
function ProviderAutoCompleteSearch() {  
}  
  
ProviderAutoCompleteSearch.prototype = {  
  
  classID: CLASS_ID,  
  classDescription : CLASS_NAME,  
  contractID : CONTRACT_ID,  
  
  findUsername: function _findUsername(passwordManager, results, realm, pattern) {
    try {
	    var logins = [];
//	    log("findUsername realm=" + realm);
	    var logins = passwordManager.findLogins(
	        {}, 
	        realm, 
	        "", 
	        null);
//	    log("findUsername logins.length=" + logins.length);
	    for (var i=0; i<logins.length;i++) {
	      var login = logins[i];
//	      log("findUsername login.username=" + login.username);
	      var newResult = pattern.replace("{username}", login.username);
	      results.push(newResult);
	    }
	    if (logins.length == 0) {
	    	results.push(pattern);
	    }
	    return results;
    } catch (e) {
      Components.utils.reportError(e);
    }
  },
  
  /**
	 * Searches for a given string and notifies a listener (either
	 * synchronously or asynchronously) of the result
	 * 
	 * @param searchString
	 *            the string to search for
	 * @param searchParam
	 *            an extra parameter
	 * @param previousResult
	 *            a previous result to use for faster searchinig
	 * @param listener
	 *            the listener to notify when the search is complete
	 */  
  startSearch: function(searchString, searchParam, previousResult, listener) {
    try {
      var  passwordManager = Services.logins;

      var results = ['https://yahoo.com/',
                     'https://www.google.com/accounts/o8/id'];
      results = this.findUsername(passwordManager, results, 'https://accounts.google.com', 'http://www.google.com/profiles/{username}');
      results = this.findUsername(passwordManager, results, 'https://www.myopenid.com', 'https://{username}.myopenid.com/');
      results = this.findUsername(passwordManager, results, 'https://my.screenname.aol.com/', 'https://openid.aol.com/{username}');
      results = this.findUsername(passwordManager, results, 'https://pip.verisignlabs.com', 'https://{username}.pip.verisignlabs.com/');
      results = this.findUsername(passwordManager, results, 'https://claimid.com', 'https://claimid.com/{username}');
      var autocomplete_result = new ProviderAutoCompleteResult(searchString,  
          Ci.nsIAutoCompleteResult.RESULT_SUCCESS, 0, "", results, null);  
    
      listener.onSearchResult(this, autocomplete_result);  
    } catch (e) {
      Components.utils.reportError(e);
      try {
        var autocomplete_result = new ProviderAutoCompleteResult(searchString,  
            Ci.nsIAutoCompleteResult.RESULT_FAILURE, 0, e + "", null, null);  
      
        listener.onSearchResult(this, autocomplete_result); 
      } catch (e) {}
    }
  },  
  
  /**
	 * Stops an asynchronous search that is in progress
	 */  
  stopSearch: function() {  
  },  
  
  QueryInterface: XPCOMUtils.generateQI([ Ci.nsIAutoCompleteSearch ])  
};  
  
// The following line is what XPCOM uses to create components
const NSGetFactory =  
  XPCOMUtils.generateNSGetFactory([ ProviderAutoCompleteSearch ]);  